import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import os
import logging
from datetime import datetime

logger = logging.getLogger(__name__)


def plot_loss_curve(results):
    """
    @brief 使用seaborn绘制不同基模型的AdaBoost中Loss随基模型数量增加的变化曲线
    @param results: 列表，每个元素为{'model': ..., 'loss': ...}，其中loss为一个列表，表示不同基模型数量下的Loss值。

    @details
    该函数将结果转换为DataFrame格式，以便使用seaborn绘图。然后绘制每个模型的Loss曲线，并保存为PNG文件。

    @exception Exception: 如果结果格式不正确或绘图失败，将抛出异常
    @return None
    """
    out_dir='fig'
    plt.figure(figsize=(16, 9))

    # 构建DataFrame以便seaborn绘图
    data = []
    for result in results:
        model = result['model']
        if result['loss'] is not None:
            for i, loss in enumerate(result['loss']):
                data.append({'Model': model, 'Estimator': i+1, 'Loss': loss})
    df = pd.DataFrame(data)

    # 保存数据表到 eval_result 目录
    os.makedirs('eval_result', exist_ok=True)
    loss_table_path = os.path.join('eval_result', 'loss_curve_table.csv')
    df.to_csv(loss_table_path, index=False)
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    logger.info(f"[{now}] Loss曲线数据表已保存到 {loss_table_path}")

    sns.lineplot(data=df, x='Estimator', y='Loss', hue='Model', marker='o')
    plt.xlabel('Number of Base Estimators')
    plt.ylabel('Loss')
    plt.title('AdaBoost Loss Curve for Different Base Models')
    plt.legend()
    plt.tight_layout()

    # 添加时间戳到文件名
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    filename = os.path.join(out_dir, f'loss_curve_{timestamp}.png')
    plt.savefig(filename)
    plt.close()

    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    logger.info(f"[{now}] Loss曲线已保存到 {filename}")


def plot_model_results_bar(results):
    """
    @brief 绘制每个模型在给定数据集上的评估结果柱状图
    @param results: 列表，每个元素为{'model': ..., 'accuracy': ..., 'f1': ...}

    @details
    该函数将结果转换为DataFrame格式，并使用seaborn绘制每个模型的评估结果柱状图。
    保存的图像文件名包含时间戳，以便于版本管理。

    @exception Exception: 如果结果格式不正确或绘图失败，将抛出异常
    @return None
    """
    out_dir='fig'
    df = pd.DataFrame(results)
    metrics = [col for col in df.columns if col not in ['model', 'train_time', 'loss']]

    for metric in metrics:
        plt.figure(figsize=(16, 9))
        sns.barplot(data=df, x='model', y=metric)
        plt.ylabel(metric.capitalize())
        plt.xlabel('Model')
        plt.title(f'Model {metric.capitalize()} Results')
        plt.ylim(0, 1)
        plt.tight_layout()

        # 添加时间戳到文件名
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        filename = os.path.join(out_dir, f'model_{metric}_bar_{timestamp}.png')
        plt.savefig(filename)
        plt.close()

        now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        logger.info(f"[{now}] {metric} 柱状图已保存到 {filename}")